<!DOCTYPE html>
<html lang="zh-CN" class="h-full">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>RAG Chat</title>
    <script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="h-full bg-gradient-to-br from-slate-900 via-slate-950 to-slate-900 text-slate-100">
<main class="min-h-full flex items-center justify-center px-4 py-10">
    <div class="w-full max-w-4xl bg-white/5 backdrop-blur-xl border border-white/10 rounded-[32px] shadow-[0_25px_80px_rgba(15,23,42,.45)] p-8 flex flex-col gap-8">
        <header class="text-center space-y-3">
            <div class="inline-flex items-center gap-2 px-4 py-1.5 bg-white/10 rounded-full text-sm tracking-wide text-indigo-200">
                <span class="text-indigo-400 text-lg">✦</span>
                <span>RAG · 对话演示</span>
            </div>
            <h1 class="text-3xl font-semibold text-white">你好，我是接入知识库的助手</h1>
            <p class="text-slate-300 text-sm">当前使用模型 deepseek-r1:1.5b，检索标签 demo。发送问题即可开始。</p>
        </header>

        <section id="messageContainer" class="flex-1 min-h-[240px] max-h-[420px] overflow-y-auto space-y-4 pr-2">
            <!-- 消息气泡 -->
        </section>

        <section class="bg-white/10 border border-white/15 rounded-[26px] p-5 shadow-inner shadow-black/20">
            <label class="block text-xs uppercase tracking-[0.3em] text-slate-400 mb-2">输入问题</label>
            <div class="flex items-center gap-3">
                <input id="messageInput"
                       type="text"
                       placeholder="例如：雅思备考从哪里开始？"
                       class="flex-1 bg-white/5 border border-white/10 rounded-2xl px-4 py-3 text-base text-white placeholder:text-slate-500 focus:outline-none focus:ring-2 focus:ring-indigo-400/60"
                       onkeypress="handleKeyPress(event)">
                <button id="sendButton"
                        onclick="sendMessage()"
                        class="h-12 w-12 rounded-2xl bg-indigo-500 text-white text-xl flex items-center justify-center shadow-lg shadow-indigo-900/50 hover:bg-indigo-400 transition">
                    ↑
                </button>
            </div>
        </section>
    </div>
</main>

<script>
    const DEFAULT_MODEL = 'deepseek-r1:1.5b';
    const DEFAULT_RAG_TAG = 'demo';

    const messageContainer = document.getElementById('messageContainer');
    const messageInput = document.getElementById('messageInput');
    const sendButton = document.getElementById('sendButton');
    let currentEventSource = null;

    function addMessage(content, role = 'assistant', streaming = false) {
        const wrapper = document.createElement('div');
        wrapper.className = `flex ${role === 'user' ? 'justify-end' : 'justify-start'}`;

        const bubble = document.createElement('div');
        bubble.className = [
            'max-w-[80%] px-5 py-3 rounded-3xl text-sm leading-relaxed shadow',
            role === 'user'
                ? 'bg-indigo-500 text-white shadow-indigo-900/40'
                : 'bg-white/10 text-slate-100 border border-white/10'
        ].join(' ');

        bubble.innerHTML = content;
        wrapper.appendChild(bubble);
        messageContainer.appendChild(wrapper);
        messageContainer.scrollTop = messageContainer.scrollHeight;

        if (streaming) {
            bubble.dataset.streaming = 'true';
        }
        return bubble;
    }

    function updateStreamingMessage(element, text, done = false) {
        if (!element) return;
        element.innerHTML = done ? text : `${text}<span class="ml-1 animate-pulse">…</span>`;
        messageContainer.scrollTop = messageContainer.scrollHeight;
    }

    function setDisabled(disabled) {
        messageInput.disabled = disabled;
        sendButton.disabled = disabled;
        sendButton.classList.toggle('opacity-60', disabled);
        sendButton.classList.toggle('cursor-not-allowed', disabled);
    }

    function sendMessage() {
        const message = messageInput.value.trim();
        if (!message) {
            alert('请输入问题');
            return;
        }

        messageInput.value = '';
        messageInput.focus();
        addMessage(message, 'user');
        const assistantBubble = addMessage('<span class="animate-pulse text-slate-300">正在思考…</span>', 'assistant', true);

        if (currentEventSource) {
            currentEventSource.close();
        }

        const params = new URLSearchParams({
            model: DEFAULT_MODEL,
            ragTag: DEFAULT_RAG_TAG,
            message
        });
        const apiUrl = `http://localhost:8090/api/v1/ollama/generate_stream_rag?${params.toString()}`;

        currentEventSource = new EventSource(apiUrl);
        setDisabled(true);
        let buffer = '';

        currentEventSource.onmessage = (event) => {
            try {
                const data = JSON.parse(event.data);
                const content = data.result?.output?.content || '';
                const finishReason = data.result?.metadata?.finishReason;

                if (content) {
                    buffer += content;
                    updateStreamingMessage(assistantBubble, buffer, false);
                }

                if (finishReason === 'STOP') {
                    currentEventSource?.close();
                    currentEventSource = null;
                    updateStreamingMessage(assistantBubble, buffer || '（模型未返回内容）', true);
                    setDisabled(false);
                }
            } catch (err) {
                console.error('解析错误:', err);
            }
        };

        currentEventSource.onerror = () => {
            updateStreamingMessage(assistantBubble, '⚠️ 连接出错，请稍后重试。', true);
            currentEventSource?.close();
            currentEventSource = null;
            setDisabled(false);
        };
    }

    function handleKeyPress(event) {
        if (event.key === 'Enter' && !event.shiftKey) {
            event.preventDefault();
            sendMessage();
        }
    }

    addMessage('你好！我是接入知识库的助手，会结合标签 <span class=\"font-semibold\">demo</span> 中的内容为你解答问题。');
</script>
</body>
</html>
